/*
* Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: connectionengine.cpp.
*/

#include <qbluetoothlocaldevice.h>

#include <QtCore/QDebug>

#include "connectionengine.h"
#include "nfcaiwwrapper.h"
#include "btserver.h"
#include "btclient.h"

//! Length of Bluetooth address in bytes
static const int BT_ADDRESS_LENGTH = 6;

/*!
    Port number, which is used when establishing a Bluetooth connection between
    two devices. The port number is hard coded because current NFC services
    don't have support for sharing the port information between devices.
*/
static const int BT_SERVER_PORT = 15;

ConnectionEngine::ConnectionEngine(QObject *parent) :
    QObject(parent), m_client(0), m_server(0), m_aiwWrapper(0)

{
    m_server = new BtServer(this);

    QBluetoothLocalDevice myDevice;
    m_server->startServer( myDevice.address(), BT_SERVER_PORT );

    connect(m_server, SIGNAL(newClient(const QString&)), this, SLOT(clientConnected(const QString&)));
    connect(m_server, SIGNAL(messageReceived(const QByteArray&)), this, SLOT(newMessage(const QByteArray&)));
    connect(m_server, SIGNAL(clientDisconnected(const QString&)), this, SLOT(clientDisconnected(const QString&)));
}

ConnectionEngine::~ConnectionEngine()
{
    delete m_aiwWrapper;
    delete m_server;
    delete m_client;
}

void ConnectionEngine::openConnection()
{
    qDebug() << "ConnectionEngine::openConnection";
    if ( !m_aiwWrapper )
    {
        m_aiwWrapper = new NfcAiwWrapper();
        connect( m_aiwWrapper, SIGNAL(connectionInfoReceived(QByteArray)),
                this, SLOT(readConnectionInfo(QByteArray)));
    }
    m_aiwWrapper->startEasySetup();
}

void ConnectionEngine::closeConnection()
{
    qDebug() << "ConnectionEngine::closeConnection";
    if ( m_client )
    {
        m_client->closeClient();
    }
    else if ( m_server )
    {
        m_server->closeClient();
    }
}

void ConnectionEngine::shareData(const QByteArray &sharedData)
{
    qDebug() << "ConnectionEngine::shareData";
    if ( sharedData.length() )
    {
        if ( m_client )
        {
            m_client->writeSocket( sharedData );
        }
        else if ( m_server )
        {
            m_server->writeSocket( sharedData );
        }
    }
}

void ConnectionEngine::readConnectionInfo(const QByteArray &connectionInfo)
{
    int index = 1; // Jump over KPeerDeviceNameEasyDataType definition.
    quint8 nameLength = connectionInfo.at(index);
    index++;
    m_deviceName = QString( connectionInfo.mid( index, nameLength ).constData() );

    index += nameLength;
    index++; // Jump over EBluetooth definition.

    QByteArray addr = connectionInfo.mid( index, BT_ADDRESS_LENGTH );

    m_deviceAddress = QBluetoothAddress( formatAddress( addr ) );

    qDebug() << "Remote address: " << m_deviceAddress.toString();
    // Delete old client if one exists.
    if ( m_client )
    {
        delete m_client;
        m_client = 0;
    }

    m_client = new BtClient( this );
    m_client->startClient( m_deviceAddress, BT_SERVER_PORT );

    connect(m_client, SIGNAL(connected(const QString&)), this, SLOT(handleConnected(const QString&)));
    connect(m_client, SIGNAL(connectionClosed()), this, SLOT(disconnected()));
    connect(m_client, SIGNAL(messageReceived(const QByteArray&)), this, SLOT(newMessage(const QByteArray&)));
}

void ConnectionEngine::clientConnected(const QString &clientName)
{
    qDebug() << "Client " << clientName << "connected";
    emit newConnection( clientName );
}

void ConnectionEngine::clientDisconnected(const QString &clientName)
{
    qDebug() << "Client " << clientName << "disconnected";
    emit connectionClosed(clientName);
}

void ConnectionEngine::handleConnected(const QString &clientName)
{
    qDebug() << "Connected to " << clientName;
    emit newConnection( clientName );
}

void ConnectionEngine::disconnected()
{
    qDebug() << "Connection closed";
    emit connectionClosed( m_deviceName );
}

void ConnectionEngine::newMessage(const QByteArray &message)
{
    qDebug() << "ConnectionEngine::newMessage";
    emit messageReceived(message);
}

QString ConnectionEngine::formatAddress( const QByteArray &address )
{
    QString addrStr;
    for ( int i(0) ; i < address.count() ; i++)
    {
        addrStr.append( QString("%1").arg( static_cast<int>(address[i]), 2, 16, QLatin1Char('0') ));
    }
    return addrStr;
}
